/*
 * @Author: wuqingchun
 * @Date: 2024-06-24 16:22:47
 * @Description: 
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-06-28 08:42:45
 */

#include <thread>
#include <cassert>

int g_iWX, g_iWY;
int g_iRA, g_iRB;

#define barrier() __asm__ volatile ("":::"memory")

#define mb() __asm__ volatile("mfence":::"memory")
#define rmb() __asm__ volatile("lfence":::"memory")
#define wmb() __asm__ volatile("sfence":::"memory")

class CAppMemoryBarrier
{
public:
    
    void CaseNoMB()
    {
        std::thread t1(&CAppMemoryBarrier::__NoMB_Write_X_Then_Read_Y, this);
        std::thread t2(&CAppMemoryBarrier::__NoMB_Write_Y_Then_Read_X, this);
        
        t1.join();
        t2.join();
        
        // A 和 B 不可能同时为0
        assert(!(m_iReadA == 0 && m_iReadB == 0));
    }

    void CaseOnlyWMB()
    {
        std::thread t1(&CAppMemoryBarrier::__OnlyWMB_Write_X_Then_Read_Y, this);
        std::thread t2(&CAppMemoryBarrier::__OnlyWMB_Write_Y_Then_Read_X, this);
        
        t1.join();
        t2.join();
        
        // A 和 B 不可能同时为0
        assert(!(m_iReadA == 0 && m_iReadB == 0));
    }

    // 同时使用读和写内存屏障
    void CaseMB()
    {
        std::thread t1(&CAppMemoryBarrier::__MB_Write_X_Then_Read_Y, this);
        std::thread t2(&CAppMemoryBarrier::__MB_Write_Y_Then_Read_X, this);
        
        t1.join();
        t2.join();
        
        // A 和 B 不可能同时为0
        assert(!(m_iReadA == 0 && m_iReadB == 0));
    }
private:
    void __NoMB_Write_X_Then_Read_Y()
    {
        m_iWriteX = 1;
        m_iReadA = m_iWriteY;
    }

    void __NoMB_Write_Y_Then_Read_X()
    {
        m_iWriteY = 1;
        m_iReadB = m_iWriteX;
    }

    void __OnlyWMB_Write_X_Then_Read_Y()
    {
        m_iWriteX = 1;
        wmb();
        m_iReadA = m_iWriteY;
    }

    void __OnlyWMB_Write_Y_Then_Read_X()
    {
        m_iWriteY = 1;
        wmb();
        m_iReadB = m_iWriteX;
    }

    void __MB_Write_X_Then_Read_Y()
    {
        m_iWriteX = 1;
        // CPU 内存屏障，保证指令 m_iWriteX = 1 在 m_iReadA = m_iWriteY 之前执行完成
        // m_iWriteX 变量被赋值为1，且修改已经同步到内存中
        // mb();
        std::atomic_thread_fence(std::memory_order_seq_cst); // 等同于mb
        m_iReadA = m_iWriteY;
    }

    void __MB_Write_Y_Then_Read_X()
    {
        m_iWriteY = 1;

        // CPU 内存屏障，保证指令 m_iWriteY = 1 在 m_iReadB = m_iWriteX 之前执行完成
        // m_iWriteY 变量被赋值为1，且修改已经同步到内存中
        // mfence指令实现了Full Barrier，相当于Store and Load Barriers。mfence指令综合了sfence指令与lfence指令的作用，强制
        // 在 mfence指令之前的store/load指令，都在该mfence指令执行之前被执行；
        // 所有在mfence指令之后的store/load指令，都在该mfence指令执行之后被执行。
        // 即，禁止对mfence指令前后store/load指令的重排序跨越mfence指令，使所有Full Barrier之前发生的操作，对所有Full Barrier之后的操作都是可见的。
        //mb();
        std::atomic_thread_fence(std::memory_order_seq_cst); // 等同于 mb

        m_iReadB = m_iWriteX;
    }

private:
    int m_iWriteX = 0;
    int m_iWriteY = 0;
    int m_iReadA = 0;
    int m_iReadB = 0;
};


int main(int argc, char** argv)
{
    int iType = 0;
    
    if (argc > 1)
        iType = atoi(argv[1]);

    CAppMemoryBarrier objApp;
    if (iType == 0)
    {
        objApp.CaseNoMB();
    }
    else if (iType == 1)
    {
        // 使用写内存屏障
        objApp.CaseOnlyWMB();
    }
    else
    {
        // 使用读写内存屏障
        objApp.CaseMB();
    }
    
    return 0;
}